package dao

import (
	"context"
	"errors"
	"gorm.io/gorm"
	"log"
)

type ElementDao interface {
	FindElementByID(ctx context.Context, id string) (*Element, error)
	DeleteById(ctx context.Context, id string) error
	EditById(ctx context.Context, id string, element *Element) error
	Insert(ctx context.Context, element *Element) error
	CheckExistByElementName(ctx context.Context, name string) (bool, error)
	List(ctx context.Context, page int, pagSize int) ([]*Element, error)
	FindAll(ctx context.Context) ([]*Element, error)
	Save(ctx context.Context, ele, existingElement *Element, trans map[string]string) error
	GetListCount(ctx context.Context) (int, error)
}
type GormElementDao struct {
	db *gorm.DB
}

func (dao *GormElementDao) GetListCount(ctx context.Context) (int, error) {
	var count int64
	err := dao.db.WithContext(ctx).Model(&Element{}).Count(&count).Error
	if err != nil {
		return 0, err
	}
	return int(count), nil
}

func (dao *GormElementDao) Save(ctx context.Context, ele, existingElement *Element, trans map[string]string) error {
	tx := dao.db.WithContext(ctx).Begin()
	if tx.Error != nil {
		return tx.Error
	}

	// 检查 Element 是否为空（除了 ID 以外）
	if existingElement.ID == 0 {
		// 插入 Element
		if err := tx.Create(&ele).Error; err != nil {
			tx.Rollback()
			return err
		}
	} else {
		// 更新 Element
		ele.ID = existingElement.ID
		updateFields := dao.getNonZeroFieldsManual(ele)
		if len(updateFields) > 0 {
			if err := tx.Model(&ele).Select(updateFields).Updates(ele).Error; err != nil {
				tx.Rollback()
				return err
			}
		}
	}

	// 处理 Translations
	var transList []*Translation
	for locale, content := range trans {
		if content == "" {
			continue
		}
		//1. 如果存在这个组件说明已经有这个组件了,则 将已经存在的组件id赋值给 Translation.ElementID
		if existingElement.ID > 0 {
			transList = append(transList, &Translation{
				ElementID: existingElement.ID,
				Locale:    locale,
				Content:   content,
			})
		} else if existingElement.ID == 0 && ele.ID != 0 {
			//2.不存在existingElement.ID ,则是新建了这个组件,将已经新建的组件id赋值给Translation
			transList = append(transList, &Translation{
				ElementID: ele.ID,
				Locale:    locale,
				Content:   content,
			})
		} else {
			//3. 仅更新组件的翻译
			transList = append(transList, &Translation{
				Locale:  locale,
				Content: content,
			})
		}

	}

	// 保存或更新 Translations
	for _, item := range transList {
		// 检查 Translation 是否已经存在
		var existingTranslation Translation
		if err := tx.Where("element_id = ? AND locale = ?", item.ElementID, item.Locale).First(&existingTranslation).Error; err != nil {
			if errors.Is(err, gorm.ErrRecordNotFound) {
				// 插入 Translation
				item.ElementID = ele.ID
				if err := tx.Create(item).Error; err != nil {
					tx.Rollback()
					return err
				}
			} else {
				tx.Rollback()
				return err
			}
		} else {
			// 更新 Translation
			if err := tx.Model(&existingTranslation).
				Where("element_id = ? and locale = ?", existingTranslation.ElementID, existingTranslation.Locale).
				Updates(map[string]interface{}{"Content": item.Content}).Error; err != nil {
				tx.Rollback()
				return err
			}
		}
	}
	return tx.Commit().Error
}

func (dao *GormElementDao) List(ctx context.Context, page int, pageSize int) ([]*Element, error) {
	var elements []*Element
	offset := (page - 1) * pageSize
	// 使用分页参数进行查询
	err := dao.db.WithContext(ctx).Offset(offset).Limit(pageSize).Find(&elements).Error
	if err != nil {
		return nil, err
	}
	return elements, err
}

func NewElementDao(db *gorm.DB) ElementDao {
	return &GormElementDao{db: db}
}

// CheckExistByElementName 检查语言是否存在
func (dao *GormElementDao) CheckExistByElementName(ctx context.Context, name string) (bool, error) {
	var existing Element
	err := dao.db.WithContext(ctx).Where("name = ?", name).First(&existing).Error
	if err != nil {
		return false, err
	}
	return true, nil
}

// Insert 添加组件
func (dao *GormElementDao) Insert(ctx context.Context, element *Element) error {
	return dao.db.WithContext(ctx).Create(&element).Error
}

// EditById 编辑组件
func (dao *GormElementDao) EditById(ctx context.Context, id string, element *Element) error {
	return dao.db.WithContext(ctx).Model(&Element{}).Where("id = ?", id).Updates(element).Error
}

// FindElementByID 根据id 查找对应组件
func (dao *GormElementDao) FindElementByID(ctx context.Context, id string) (*Element, error) {
	var element *Element
	err := dao.db.WithContext(ctx).Where("id = ?", id).First(&element).Error
	return element, err
}

// DeleteById 根据id删除组件 以及组件下的所有翻译
func (dao *GormElementDao) DeleteById(ctx context.Context, id string) error {
	// 开始事务
	tx := dao.db.WithContext(ctx).Begin()
	if tx.Error != nil {
		log.Printf("开始事务失败: %v", tx.Error)
		return tx.Error
	}

	// 删除 translations 表中的相关记录
	if err := tx.Where("element_id = ?", id).Delete(&Translation{}).Error; err != nil {
		log.Printf("删除 translations 记录失败: %v", err)
		tx.Rollback()
		return err
	}

	// 删除 elements 表中的记录
	if err := tx.Where("id = ?", id).Delete(&Element{}).Error; err != nil {
		log.Printf("删除 elements 记录失败: %v", err)
		tx.Rollback()
		return err
	}

	// 提交事务
	if err := tx.Commit().Error; err != nil {
		log.Printf("提交事务失败: %v", err)
		return err
	}

	return nil
}

// FindAll 查询所有组件
func (dao *GormElementDao) FindAll(ctx context.Context) ([]*Element, error) {
	var elements []*Element
	// 使用分页参数进行查询
	err := dao.db.WithContext(ctx).Find(&elements).Error
	if err != nil {
		return nil, err
	}
	return elements, err
}

func (dao *GormElementDao) getNonZeroFieldsManual(ele *Element) []string {
	var fields []string
	if ele.Name != "" {
		fields = append(fields, "Name")
	}
	if ele.Type != "" {
		fields = append(fields, "Type")
	}
	if ele.Description != "" {
		fields = append(fields, "Description")
	}
	return fields
}

type Element struct {
	ID          int    `gorm:"primaryKey;type:int" json:"id"`
	Name        string `gorm:"type:varchar(255);not null" json:"name"`
	Type        string `gorm:"type:varchar(50);not null" json:"type"`
	Description string `gorm:"type:text" json:"description"`
}

func (Element) TableName() string {
	return "elements"
}
